/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/cat.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../msg_aio/head.h"
#include "../config/head.h"
#include "../macro/head.h"
#include "../impl/head.h"
#include "../impl/head.h"
#include "../msg/head.h"
#include "msg_net.h"
#include "net_tcp.h"

namespace cat
{

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static int server_num_n = 0;

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    net_tcp::net_tcp()
    {
    }

    net_tcp::~net_tcp()
    {
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int net_tcp::set_server_num( int nNum )
    {
        int ret = 0;
        server_num_n = nNum;
        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // proc

    int net_tcp::proc( xos::i_msg *& pMsg )
    {
        int ret = 1;

        int nMsg = pMsg->get_int( 0, 0 );

        switch( nMsg )
        {
        case NET_TCP_NEED_RELEASE:
            {
                on_need_release( pMsg );
            }
            break;
        case NET_TCP_NEED_CLOSE:
            {
                on_need_close( pMsg );
            }
            break;
        case NET_TCP_DATA_ERR:
            {
                on_data_err( pMsg );
            }
            break;
        case NET_TCP_INIT:
            {
                on_init( pMsg );
            }
            break;
        case NET_TCP_ACCEPT:
            {
                on_accept( pMsg );
            }
            break;
        case NET_TCP_CONNECT:
            {
                on_connect( pMsg );
            }
            break;
        case NET_TCP_RECV:
            {
                on_recv( pMsg );
            }
            break;
        case NET_TCP_SEND:
            {
                on_send( pMsg );
            }
            break;
        case NET_TCP_SHUTDOWN:
            {
                on_shutdown( pMsg );
            }
            break;
        case NET_TCP_CLOSE:
            {
                on_close( pMsg );
            }
            break;
        default:
            {
                ret = 0;
            }
            break;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int net_tcp::on_need_release( xos::i_msg *& pMsg )
    {
        int ret = 0;
        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        pConnect->helper_release();
        return ret;
    }

    int net_tcp::on_need_close( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        
        if( 0 == ret )
        {
            aio_tcp obj;
            ret = obj.post_close( pConnect, 0, 0 );
        }

        return ret;
    }

    int net_tcp::on_data_err( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );

        if( 0 == ret )
        {
            aio_tcp obj;
            ret = obj.post_close( pConnect, 1, 0 );
            pConnect->un_lock_server();
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_tcp::on_init( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        tcp * pTcp = pConnect->m_pTcp;
        bool bRet = pMsg->get_bool( 0, 0 );

        if( bRet )
        {
            if( 0 == --server_num_n )
            {
                msg::notify_main_main( pMsg, MAIN_STARTED, false );
            }
        }
        else
        {
            tcp::term( pTcp );
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // m_lpData[2] : ClientKey
    // 
    int net_tcp::on_accept( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        tcp * pTcp = pConnect->m_pTcp;
        bool bRet = pMsg->get_bool( 0, 0 );

        if( bRet )
        {
            LOG4( "accept : (%s:%d)(%s:%d)", pTcp->m_local_ip.c_str(), pTcp->m_nLocalPort, pTcp->m_peer_ip.c_str(), pTcp->m_nPeerPort );
        }
        else
        {
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_tcp::on_connect( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        tcp * pTcp = pConnect->m_pTcp;
        bool bRet = pMsg->get_bool( 0, 0 );

        if( bRet )
        {
            // connect success
        }
        else
        {
            tcp::term( pTcp );
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : recv len
    // m_lpBuf[0] : recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_tcp::on_recv( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        xos::i_buf * pBuf = pMsg->get_buf( 0, 0 );
        bool bRet = pMsg->get_bool( 0, 0 );
        task * pTask = pConnect->m_pTask;
        int nRecvLen = 0;
        
        if( ( 0 == ret ) && !bRet )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            pMsg->set_void( 0, pTask );
            pBuf->get_len( &nRecvLen );
            pBuf = 0;
        }

        if( ( 0 == ret ) && pConnect->http_data() )
        {
            tcp * pTcp = pConnect->m_pTcp;
            LOG4( "recv : (%s:%d)(%s:%d)(%d), len = %d", pTcp->m_local_ip.c_str(), pTcp->m_nLocalPort, pTcp->m_peer_ip.c_str(), pTcp->m_nPeerPort, pConnect->m_nLockNum, 
                nRecvLen );
            msg::notify_package( pMsg, PACKET_HTTP_UN_ENCRYPT, false );
            ret = 1;
        }

        if( ( 0 == ret ) && pConnect->tcp_data() )
        {
            msg::notify_package( pMsg, PACKET_TCP_UN_ENCRYPT, false );
            ret = 1;
        }

        xos_stl::release_interface( pBuf );

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_nData[1] : send bytes
    // m_lpBuf[0] : send buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_tcp::on_send( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        xos::i_buf * pBuf = pMsg->get_buf( 0, 0 );
        bool bRet = pMsg->get_bool( 0, 0 );

        if( ( 0 == ret ) && bRet )
        {
            tcp * pTcp = pConnect->m_pTcp;
            int nLen = 0;
            pBuf->get_len( &nLen );
            LOG4( "send : (%s:%d)(%s:%d)(%d), len = %d", pTcp->m_local_ip.c_str(), pTcp->m_nLocalPort, 
                pTcp->m_peer_ip.c_str(), pTcp->m_nPeerPort, 
                pConnect->m_nLockNum, 
                nLen );
        }

        if( ( 0 == ret ) && ( pConnect->m_pCloseAfterSend == pBuf ) )
        {
            pConnect->set_timeout_time_s( config::get()->close_wait_time_s );
            pConnect->m_pCloseAfterSend = ( xos::i_buf* )1;
            LOG4( "recv close buf, set timeout..." );
            pConnect->post_shut_down( xos::i_socket::XOS_SD_SEND );
            ret = 1;
        }

        if( ( 0 == ret ) && ( pConnect->m_pQuitAfterSend == pBuf ) )
        {
            pConnect->set_timeout_time_s( config::get()->quit_wait_time_s );
            pConnect->m_pQuitAfterSend = ( xos::i_buf* )1;
            LOG4( "recv quit buf, set timeout..." );
            msg::notify_main_main( MAIN_QUITING, false );
            ret = 1;
        }

        xos_stl::release_interface( pBuf );

        return ret;
    }

    int net_tcp::on_shutdown( xos::i_msg *& pMsg )
    {
        int ret = 0;

        //connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        //tcp * pTcp = pConnect->m_pTcp;
        //bool bRet = pMsg->get_bool( 0, 0 );

        if( 0 == ret )
        {
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nData[0] : cmd type
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int net_tcp::on_close( xos::i_msg *& pMsg )
    {
        int ret = 0;

        connection * pConnect = (connection *)pMsg->get_void( 0, 0 );
        task * pTask = pConnect->m_pTask;
        tcp * pTcp = pConnect->m_pTcp;

        LOG4( "closed : (%s:%d)(%s:%d)(%d)", pTcp->m_local_ip.c_str(), pTcp->m_nLocalPort, pTcp->m_peer_ip.c_str(), pTcp->m_nPeerPort, pConnect->m_nLockNum );

        pMsg->set_void( 0, pTask );
        pConnect->set_closed();

        if( pConnect->http_data() )
        {
            msg::notify_package( pMsg, PACKET_HTTP_UN_ENCRYPT_FLUSH, false );
        }
        else if( pConnect->tcp_data() )
        {
            msg::notify_package( pMsg, PACKET_TCP_UN_ENCRYPT_FLUSH, false );
        }
        else
        {
            pConnect->un_lock_server();
        }

        return ret;
    }

} // cat
